from __future__ import annotations

"""
交易执行管道服务
-----------------
实现 D 阶段的各个组件：快照、决策、风控、执行、对账、PnL计算
包含防重复下单机制
"""

import datetime as dt
import hashlib
import json
import logging
from decimal import Decimal
from typing import Any, Dict, List, Optional, Tuple

from sqlalchemy import select, update, and_
from sqlalchemy.ext.asyncio import AsyncSession

from ..models import (
    Decision,
    DecisionStatus,
    Fill,
    PnLDaily,
    Run,
    RunMode,
    Snapshot,
    TradingOrder,
)
from ..services.mcp_session import mcp

logger = logging.getLogger(__name__)


def generate_action_fingerprint(action_json: Dict[str, Any]) -> str:
    """生成动作指纹（去掉price和时间相关字段）
    
    用于去重：相同动作在冷却窗内不会重复执行
    """
    # 复制并移除可变字段
    fingerprint_data = {
        "action": action_json.get("action"),
        "exchange": action_json.get("exchange"),
        "symbol": action_json.get("symbol"),
        "side": action_json.get("side"),
        "order_type": action_json.get("order_type"),
        "amount": action_json.get("amount"),
        # 不包含 price（限价单价格可能变化）
        # 不包含 account_name, run_id（这些是上下文）
    }
    fingerprint_str = json.dumps(fingerprint_data, sort_keys=True)
    return hashlib.md5(fingerprint_str.encode()).hexdigest()[:16]


def generate_client_order_id(
    run_id: str,
    symbol: str,
    side: str,
    snapshot_digest: Optional[str] = None,
) -> str:
    """生成全局唯一的 client_order_id
    
    格式：{run_id}-{symbol}-{side}-{epoch_ms}-{hash8}
    
    其中 hash8 基于 snapshot_digest（如果提供）或其他唯一性因子
    确保即使同一 tick 重复执行也不会产生相同的 COID
    """
    import time
    epoch_ms = int(time.time() * 1000)
    
    # 如果有快照摘要，用于生成hash；否则用随机因子
    if snapshot_digest:
        hash_input = f"{run_id}{symbol}{side}{epoch_ms}{snapshot_digest}"
    else:
        import secrets
        hash_input = f"{run_id}{symbol}{side}{epoch_ms}{secrets.token_hex(4)}"
    
    hash8 = hashlib.md5(hash_input.encode()).hexdigest()[:8]
    return f"{run_id}-{symbol}-{side}-{epoch_ms}-{hash8}"


async def check_duplicate_action(
    session: AsyncSession,
    action_json: Dict[str, Any],
    run_id: str,
    cooldown_seconds: int = 30,
) -> Tuple[bool, Optional[str]]:
    """检查是否为重复动作（指纹去重 + 冷却窗）
    
    返回: (is_duplicate, reason)
    """
    fingerprint = generate_action_fingerprint(action_json)
    
    # 查询最近执行的相同指纹决策
    recent_stmt = (
        select(Decision)
        .where(
            and_(
                Decision.run_id == run_id,
                Decision.action_json.isnot(None),
                Decision.ts >= dt.datetime.now(dt.timezone.utc) - dt.timedelta(seconds=cooldown_seconds)
            )
        )
        .order_by(Decision.ts.desc())
        .limit(10)
    )
    
    result = await session.execute(recent_stmt)
    recent_decisions = result.scalars().all()
    
    for recent_decision in recent_decisions:
        recent_fingerprint = generate_action_fingerprint(recent_decision.action_json)
        if recent_fingerprint == fingerprint:
            # 检查状态：如果已执行或正在执行，则认为是重复
            if recent_decision.status in [DecisionStatus.EXECUTING, DecisionStatus.EXECUTED]:
                time_diff = (dt.datetime.now(dt.timezone.utc) - recent_decision.ts).total_seconds()
                if time_diff < cooldown_seconds:
                    return True, f"相同动作在{cooldown_seconds}秒内已执行（{time_diff:.1f}秒前）"
    
    return False, None


async def check_existing_orders(
    session: AsyncSession,
    run_id: str,
    exchange: str,
    symbol: str,
    side: str,
    order_type: str,
) -> Optional[TradingOrder]:
    """检查是否存在未完成的同类订单"""
    # 未完成状态
    pending_statuses = ["sent", "partial", "pending", "open"]
    
    stmt = select(TradingOrder).where(
        and_(
            TradingOrder.run_id == run_id,
            TradingOrder.exchange == exchange,
            TradingOrder.symbol == symbol,
            TradingOrder.side == side,
            TradingOrder.order_type == order_type,
            TradingOrder.status.in_(pending_statuses)
        )
    ).order_by(TradingOrder.created_at.desc()).limit(1)
    
    result = await session.execute(stmt)
    return result.scalar_one_or_none()


async def try_insert_pending_order(
    session: AsyncSession,
    client_order_id: str,
    run_id: str,
    exchange: str,
    symbol: str,
    side: str,
    order_type: str,
    amount: Decimal,
    price: Optional[Decimal] = None,
) -> Tuple[bool, Optional[TradingOrder]]:
    """尝试插入预订单（幂等检查）
    
    返回: (success, existing_order)
    如果 client_order_id 已存在，返回 False 和现有订单
    """
    try:
        # 先检查是否已存在
        stmt = select(TradingOrder).where(
            TradingOrder.client_order_id == client_order_id
        )
        result = await session.execute(stmt)
        existing = result.scalar_one_or_none()
        
        if existing:
            logger.info(f"预订单已存在: client_order_id={client_order_id}")
            return False, existing
        
        # 插入预订单
        pending_order = TradingOrder(
            order_id=client_order_id,  # 临时使用 client_order_id 作为 order_id
            client_order_id=client_order_id,
            run_id=run_id,
            exchange=exchange,
            symbol=symbol,
            side=side,
            order_type=order_type,
            price=price,
            amount=amount,
            status="pending",  # 待执行状态
        )
        session.add(pending_order)
        await session.flush()  # 先 flush 检查 UNIQUE 约束
        
        return True, pending_order
        
    except Exception as e:
        # UNIQUE 约束冲突或其他错误
        await session.rollback()
        logger.warning(f"预订单插入失败（可能重复）: {e}")
        
        # 再次查询
        stmt = select(TradingOrder).where(
            TradingOrder.client_order_id == client_order_id
        )
        result = await session.execute(stmt)
        existing = result.scalar_one_or_none()
        return False, existing


# ========== D1: 快照任务（Snapshotter）==========

async def create_snapshot(
    session: AsyncSession,
    run_id: str,
    exchange: str,
    symbol: str,
    account_name: str,
    risk_config: Optional[Dict[str, Any]] = None,
) -> Snapshot:
    """创建市场快照：通过 MCP 获取价格、资金费率、仓位、余额"""
    await mcp.start()
    
    if not mcp.enabled:
        raise RuntimeError("MCP 服务未启用")
    
    payload: Dict[str, Any] = {}
    risk_config = risk_config or {}
    data_sources: Dict[str, Any] = risk_config.get("data_sources", {}) or risk_config.get("connectors", {}) or {}
    enable_derivatives = risk_config.get("enable_derivatives", True)

    def _ensure_list(value: Any, default: Optional[List[str]] = None) -> List[str]:
        if value is None:
            return default[:] if default else []
        if isinstance(value, (list, tuple, set)):
            return [str(v) for v in value if v]
        return [str(value)]

    base_exchange = exchange[:-10] if exchange.endswith("_perpetual") else exchange
    spot_default = data_sources.get("spot_connector") or data_sources.get("price_connector") or base_exchange or exchange
    perp_default = data_sources.get("perp_connector") or data_sources.get("funding_connector")

    if not perp_default:
        if exchange.endswith("_perpetual"):
            perp_default = exchange
        elif base_exchange:
            perp_default = f"{base_exchange}_perpetual"
        else:
            perp_default = None

    candles_cfg = data_sources.get("candles") if isinstance(data_sources.get("candles"), dict) else {}

    price_connector = data_sources.get("price_connector") or exchange if not exchange.endswith("_perpetual") else spot_default
    if not price_connector:
        price_connector = exchange

    funding_connector = data_sources.get("funding_connector") or perp_default
    balance_connectors = _ensure_list(
        data_sources.get("balance_connectors"),
        [c for c in {spot_default, perp_default} if c],
    )
    if not balance_connectors:
        balance_connectors = [exchange]

    positions_connectors = _ensure_list(
        data_sources.get("positions_connectors"),
        [perp_default] if enable_derivatives and perp_default else [exchange],
    )

    balance_accounts = _ensure_list(
        data_sources.get("accounts") or data_sources.get("account_names"),
        [account_name],
    )
    positions_accounts = _ensure_list(
        data_sources.get("positions_accounts") or data_sources.get("account_names"),
        [account_name],
    )

    trading_pair_override = data_sources.get("trading_pair") or symbol
    trading_pairs_override = data_sources.get("trading_pairs")
    if trading_pairs_override:
        trading_pairs = _ensure_list(trading_pairs_override, [symbol])
    else:
        trading_pairs = [trading_pair_override]

    candles_connector = candles_cfg.get("connector_name") or data_sources.get("candles_connector") or price_connector
    candles_interval = candles_cfg.get("interval") or data_sources.get("candles_interval") or "10m"
    candles_days = candles_cfg.get("days") or data_sources.get("candles_days") or 7
    try:
        candles_days = int(candles_days)
        if candles_days <= 0:
            candles_days = 7
    except Exception:
        candles_days = 7

    def _deserialize(result: Any) -> Any:
        from ..routers.ai import _flatten_mcp_result
        text = _flatten_mcp_result(result)
        structured = getattr(result, "structuredContent", None)
        if structured:
            return structured
        if not text:
            return {}
        try:
            return json.loads(text)
        except Exception:
            return text

    def _normalize_mapping(data: Any, key_fields: Optional[List[str]] = None) -> Dict[str, Any]:
        if isinstance(data, dict):
            return data
        if isinstance(data, list):
            mapping: Dict[str, Any] = {}
            for item in data:
                if isinstance(item, dict):
                    keys = key_fields or ["trading_pair", "symbol", "pair", "market"]
                    key = next((str(item[k]) for k in keys if k in item and item[k]), None)
                    if not key:
                        key = str(len(mapping))
                    mapping[key] = item
            return mapping
        if isinstance(data, str):
            return {symbol: data}
        return {}
    
    try:
        # 1. 获取最新价
        try:
            ticker_result = await mcp.call_tool("get_prices", {
                "connector_name": price_connector,
                "trading_pairs": trading_pairs,
            })
            ticker_data = _deserialize(ticker_result)
            payload["ticker"] = _normalize_mapping(ticker_data)
        except Exception as e:
            logger.warning(f"获取价格失败: {e}")
            payload["ticker"] = {}

        # 1.1 获取 K 线（candles）
        if candles_connector and trading_pair_override:
            try:
                candles_result = await mcp.call_tool("get_candles", {
                    "connector_name": candles_connector,
                    "trading_pair": trading_pair_override,
                    "interval": candles_interval,
                    "days": candles_days,
                })
                candles_data = _deserialize(candles_result)
                payload["candles"] = candles_data if candles_data else []
            except Exception as e:
                logger.warning(f"获取 K 线失败: {e}")
                payload["candles"] = []
        else:
            payload["candles"] = []
        
        # 2. 获取资金费率（仅衍生品）
        if enable_derivatives and funding_connector:
            try:
                funding_result = await mcp.call_tool("get_funding_rate", {
                    "connector_name": funding_connector,
                    "trading_pair": trading_pair_override,
                })
                funding_data = _deserialize(funding_result)
                payload["funding"] = _normalize_mapping(funding_data)
            except Exception as e:
                logger.warning(f"获取资金费率失败: {e}")
                payload["funding"] = {}
        else:
            payload["funding"] = {}
        
        # 3. 获取 positions（过滤目标账户）
        try:
            positions_params: Dict[str, Any] = {
                "account_names": positions_accounts,
            }
            if positions_connectors:
                positions_params["connector_names"] = positions_connectors
            positions_result = await mcp.call_tool("get_positions", positions_params)
            positions_data = _deserialize(positions_result)
            filtered_mapping = _normalize_mapping(positions_data)
            if symbol:
                filtered_mapping = {
                    key: value for key, value in filtered_mapping.items()
                    if symbol in key or (isinstance(value, dict) and symbol in json.dumps(value, ensure_ascii=False))
                }
            payload["positions"] = filtered_mapping
        except Exception as e:
            logger.warning(f"获取 positions 失败: {e}")
            payload["positions"] = {}
        
        # 4. 获取 balance（过滤目标账户）
        try:
            balance_params: Dict[str, Any] = {}
            if balance_accounts:
                balance_params["accounts"] = balance_accounts
            if balance_connectors:
                balance_params["connectors"] = balance_connectors
            balance_result = await mcp.call_tool("get_portfolio_balances", balance_params)
            balance_data = _deserialize(balance_result)
            payload["balance"] = _normalize_mapping(balance_data, key_fields=["asset", "currency", "symbol"])
        except Exception as e:
            logger.warning(f"获取 balance 失败: {e}")
            payload["balance"] = {}
        
        # 创建快照记录
        snapshot = Snapshot(
            run_id=run_id,
            exchange=exchange,
            symbol=symbol,
            account_name=account_name,
            payload=payload
        )
        session.add(snapshot)
        try:
            await session.commit()
            await session.refresh(snapshot)
        except Exception as commit_error:
            await session.rollback()
            logger.error(f"快照提交失败: {commit_error}")
            raise
        
        logger.info(f"快照创建成功: run_id={run_id}, exchange={exchange}, symbol={symbol}")
        return snapshot
        
    except Exception as e:
        # 确保 session 被 rollback
        try:
            await session.rollback()
        except:
            pass
        logger.error(f"创建快照失败: {e}")
        raise


# ========== D2: 决策任务（Decisioner）==========

async def create_decision(
    session: AsyncSession,
    run_id: str,
    snapshot_id: int,
    snapshot_exchange: str,
    snapshot_symbol: str,
    snapshot_payload: Dict[str, Any],
    risk_config: Dict[str, Any],
    context: Dict[str, Any],
) -> Decision:
    """调用风控规划器创建决策"""
    from ..routers.risk_planner import (
        ContextModel,
        RiskConfigModel,
        RiskPlannerRequest,
        SnapshotModel,
    )
    
    # 参数已经包含所有需要的值，无需再访问 snapshot 对象
    
    # 构建请求
    req = RiskPlannerRequest(
        snapshot=SnapshotModel(
            exchange=snapshot_exchange,
            symbol=snapshot_symbol,
            ticker=snapshot_payload.get("ticker", {}),
            funding=snapshot_payload.get("funding", {}),
            positions=snapshot_payload.get("positions", {}),
            balance=snapshot_payload.get("balance", {}),
            candles=snapshot_payload.get("candles")
        ),
        risk_config=RiskConfigModel(**risk_config),
        context=ContextModel(**context)
    )
    
    # 调用规划器（导入路由函数）
    from ..routers.risk_planner import plan_action
    planner_response = await plan_action(req)
    
    # 转换为字典
    action_json = planner_response.model_dump()
    
    # 判断状态
    if action_json["action"] == "NOP" and "BAD_ARGS" in action_json.get("reason", ""):
        status = DecisionStatus.BAD_ARGS
    else:
        status = DecisionStatus.DRYRUN
    
    # 创建决策记录
    decision = Decision(
        run_id=run_id,
        action_json=action_json,
        status=status,
        reason=action_json.get("reason")
    )
    session.add(decision)
    try:
        await session.commit()
        await session.refresh(decision)
    except Exception as commit_error:
        await session.rollback()
        logger.error(f"决策提交失败: {commit_error}")
        raise
    
    logger.info(f"决策创建成功: decision_id={decision.id}, action={action_json.get('action')}")
    return decision


# ========== D3: 风控闸门（Risk Gate）==========

async def validate_decision(
    session: AsyncSession,
    decision: Decision,
    snapshot: Snapshot,
    risk_config: Dict[str, Any],
) -> Decision:
    """风控校验：更新决策状态为 APPROVED 或 REJECTED"""
    action_json = decision.action_json
    action = action_json.get("action")
    
    # 如果已经是 BAD_ARGS 或 NOP，直接跳过
    if decision.status == DecisionStatus.BAD_ARGS or action == "NOP":
        if action == "NOP":
            decision.status = DecisionStatus.REJECTED
            decision.reason = action_json.get("reason", "NOP 操作")
            await session.commit()
        return decision
    
    rejections: List[str] = []
    
    # 1. 白名单检查
    if action_json.get("exchange") not in risk_config.get("allowed_exchanges", []):
        rejections.append("交易所不在白名单")
    if action_json.get("symbol") not in risk_config.get("allowed_symbols", []):
        rejections.append("交易对不在白名单")
    
    # 2. 数据完整性（已有快照，基本保证）
    ticker = snapshot.payload.get("ticker", {})
    last_price = ticker.get("last") or ticker.get("price")
    if not last_price and action == "OPEN":
        rejections.append("无法获取最新价")
    
    # 3. 名义额检查（仅 OPEN）
    if action == "OPEN":
        amount = action_json.get("amount")
        if amount and last_price:
            notional = Decimal(str(amount)) * Decimal(str(last_price))
            max_notional = Decimal(str(risk_config.get("max_notional_usd", 0)))
            if notional > max_notional:
                rejections.append(f"名义额超限: {notional} > {max_notional}")
    
    # 4. 滑点检查（限价单）
    if action == "OPEN" and action_json.get("order_type") == "limit":
        price = action_json.get("price")
        if price and last_price:
            slippage_bps = abs(Decimal(str(price)) - Decimal(str(last_price))) / Decimal(str(last_price)) * 10000
            max_slippage = risk_config.get("max_slippage_bps", 0)
            if slippage_bps > max_slippage:
                rejections.append(f"滑点超限: {slippage_bps} > {max_slippage} bps")
    
    # 5. 衍生品限制
    if not risk_config.get("enable_derivatives", True):
        # 简单检查：如果有 funding 且非空，可能是衍生品
        if snapshot.payload.get("funding"):
            rejections.append("衍生品交易被禁用")
    
    # 更新状态
    if rejections:
        decision.status = DecisionStatus.REJECTED
        decision.reason = "; ".join(rejections)
    else:
        decision.status = DecisionStatus.APPROVED
        decision.reason = "风控校验通过"
    
    await session.commit()
    await session.refresh(decision)
    
    logger.info(f"风控校验完成: decision_id={decision.id}, status={decision.status}, reason={decision.reason}")
    return decision


# ========== D4: 执行器（Executor）==========

async def execute_decision(
    session: AsyncSession,
    decision: Decision,
    mode: RunMode,
    snapshot: Optional[Snapshot] = None,
    cooldown_seconds: int = 30,
) -> Optional[TradingOrder]:
    """执行决策：dry-run 或 live（带防重复下单机制）
    
    流程：
    1. 状态检查（只有 APPROVED 才能执行）
    2. 指纹去重 + 冷却窗检查
    3. 检查同类未完结订单
    4. 状态机：APPROVED -> EXECUTING
    5. 预插入订单（幂等）
    6. 下单前对账检查
    7. 执行下单
    8. 状态机：EXECUTING -> EXECUTED/ERROR
    """
    # 1. 状态检查：只有 APPROVED 才能执行（EXECUTING 需要先对账）
    if decision.status != DecisionStatus.APPROVED:
        logger.warning(f"决策状态为 {decision.status}，跳过执行: decision_id={decision.id}")
        return None
    
    action_json = decision.action_json
    action = action_json.get("action")
    
    if action == "NOP":
        decision.status = DecisionStatus.EXECUTED
        decision.result = {"status": "skipped", "reason": "NOP action"}
        await session.commit()
        return None
    
    # 2. 指纹去重 + 冷却窗检查
    is_dup, dup_reason = await check_duplicate_action(
        session, action_json, decision.run_id, cooldown_seconds
    )
    if is_dup:
        decision.status = DecisionStatus.REJECTED
        decision.reason = f"重复动作: {dup_reason}"
        await session.commit()
        logger.info(f"检测到重复动作，拒绝执行: decision_id={decision.id}, reason={dup_reason}")
        return None
    
    # 3. 检查同类未完结订单（仅 OPEN 操作）
    if action == "OPEN":
        existing_order = await check_existing_orders(
            session,
            decision.run_id,
            action_json["exchange"],
            action_json["symbol"],
            action_json["side"],
            action_json["order_type"]
        )
        if existing_order:
            decision.status = DecisionStatus.REJECTED
            decision.reason = f"同类未完结订单已存在: order_id={existing_order.order_id}"
            await session.commit()
            logger.warning(f"检测到同类未完结订单，拒绝执行: decision_id={decision.id}")
            return None
    
    # 4. 状态机：APPROVED -> EXECUTING
    decision.status = DecisionStatus.EXECUTING
    await session.commit()
    logger.info(f"决策进入执行状态: decision_id={decision.id}")
    
    # 5. Dry-run 模式（无需预插入订单）
    if mode == RunMode.shadow or mode == RunMode.paper:
        if action == "OPEN":
            result = {
                "mode": "dry_run",
                "tool": "place_order",
                "params": {
                    "connector_name": action_json["exchange"],
                    "trading_pair": action_json["symbol"],
                    "side": action_json["side"],
                    "amount": action_json["amount"],
                    "order_type": action_json["order_type"],
                    "price": action_json.get("price"),
                    "time_in_force": action_json.get("time_in_force"),
                }
            }
        elif action == "CLOSE":
            result = {
                "mode": "dry_run",
                "tool": "close_position",
                "params": {
                    "connector_name": action_json["exchange"],
                    "trading_pair": action_json["symbol"],
                    "amount": action_json.get("amount"),
                }
            }
        else:
            result = {"mode": "dry_run", "action": action}
        
        decision.result = result
        decision.status = DecisionStatus.EXECUTED
        await session.commit()
        logger.info(f"Dry-run 执行完成: decision_id={decision.id}")
        return None
    
    # 6. Live 模式（执行真实下单）
    if mode == RunMode.live:
        await mcp.start()
        if not mcp.enabled:
            decision.status = DecisionStatus.ERROR
            decision.reason = "MCP 服务不可用"
            await session.commit()
            return None
        
        try:
            # 生成快照摘要用于 client_order_id
            snapshot_digest = None
            if snapshot:
                snapshot_str = json.dumps(snapshot.payload, sort_keys=True)
                snapshot_digest = hashlib.md5(snapshot_str.encode()).hexdigest()[:8]
            
            # 生成 client_order_id
            client_order_id = generate_client_order_id(
                run_id=decision.run_id,
                symbol=action_json["symbol"],
                side=action_json["side"],
                snapshot_digest=snapshot_digest
            )
            
            if action == "OPEN":
                # 6.1 预插入订单（幂等检查）
                amount = Decimal(str(action_json["amount"]))
                price = Decimal(str(action_json["price"])) if action_json.get("price") else None
                
                success, pending_order = await try_insert_pending_order(
                    session,
                    client_order_id,
                    decision.run_id,
                    action_json["exchange"],
                    action_json["symbol"],
                    action_json["side"],
                    action_json["order_type"],
                    amount,
                    price,
                )
                
                if not success:
                    # 预订单已存在，可能是重复请求
                    logger.warning(f"预订单已存在，可能重复请求: client_order_id={client_order_id}")
                    
                    # 检查是否已有对应的订单
                    if pending_order:
                        # 如果订单状态不是 pending，说明可能已经执行过
                        if pending_order.status != "pending":
                            decision.status = DecisionStatus.EXECUTED
                            decision.result = {
                                "order_id": pending_order.order_id,
                                "client_order_id": client_order_id,
                                "status": "already_exists"
                            }
                            await session.commit()
                            logger.info(f"订单已存在，跳过执行: order_id={pending_order.order_id}")
                            return pending_order
                    
                    # 如果是 pending 状态，继续执行（可能是并发请求）
                    logger.info(f"检测到并发请求，继续执行: client_order_id={client_order_id}")
                
                # 6.2 下单前对账检查：查询数据库是否已有相同 COID 的订单（已在预插入时检查）
                
                # 6.3 调用 place_order（使用 client_order_id 作为幂等键）
                side_upper = action_json["side"].upper() if action_json.get("side") else None
                order_type_upper = action_json["order_type"].upper() if action_json.get("order_type") else None

                mcp_params = {
                    "connector_name": action_json["exchange"],
                    "trading_pair": action_json["symbol"],
                    "side": side_upper,
                    "amount": action_json["amount"],
                    "order_type": order_type_upper,
                    "client_order_id": client_order_id,  # 传递 COID 给交易所（如果支持）
                }
                if action_json.get("price") is not None:
                    mcp_params["price"] = action_json["price"]
                if action_json.get("time_in_force"):
                    mcp_params["time_in_force"] = action_json["time_in_force"].upper()
                
                mcp_result = await mcp.call_tool("place_order", mcp_params)
                from ..routers.ai import _flatten_mcp_result
                result_text = _flatten_mcp_result(mcp_result)
                result_data = json.loads(result_text) if result_text else {}
                
                # 6.4 更新订单记录（如果预插入成功，更新它；否则创建新记录）
                if success and pending_order:
                    # 更新预订单
                    pending_order.order_id = result_data.get("order_id", client_order_id)
                    pending_order.status = result_data.get("status", "sent")
                    pending_order.raw = result_data
                    order = pending_order
                else:
                    # 创建新订单记录（理论上不会到这里）
                    order = TradingOrder(
                        order_id=result_data.get("order_id", client_order_id),
                        client_order_id=client_order_id,
                        run_id=decision.run_id,
                        exchange=action_json["exchange"],
                        symbol=action_json["symbol"],
                        side=action_json["side"],
                        order_type=action_json["order_type"],
                        price=price,
                        amount=amount,
                        status=result_data.get("status", "sent"),
                        raw=result_data
                    )
                    session.add(order)
                
                await session.commit()
                
                # 7. 状态机：EXECUTING -> EXECUTED
                decision.status = DecisionStatus.EXECUTED
                decision.result = {"order_id": order.order_id, "client_order_id": client_order_id}
                await session.commit()
                
                logger.info(f"订单执行成功: order_id={order.order_id}, client_order_id={client_order_id}")
                return order
                
            elif action == "CLOSE":
                # 调用 close_position
                mcp_result = await mcp.call_tool("close_position", {
                    "connector_name": action_json["exchange"],
                    "trading_pair": action_json["symbol"],
                    "amount": action_json.get("amount"),
                })
                from ..routers.ai import _flatten_mcp_result
                result_text = _flatten_mcp_result(mcp_result)
                result_data = json.loads(result_text) if result_text else {}
                
                decision.status = DecisionStatus.EXECUTED
                decision.result = result_data
                await session.commit()
                
                logger.info(f"平仓执行成功: decision_id={decision.id}")
                return None
            
            elif action == "CANCEL":
                order_id = action_json.get("order_id")
                if not order_id:
                    decision.status = DecisionStatus.REJECTED
                    decision.reason = "CANCEL 操作缺少 order_id"
                    await session.commit()
                    return None
                
                mcp_result = await mcp.call_tool("cancel_order", {
                    "order_id": order_id,
                    "connector_name": action_json["exchange"],
                })
                
                decision.status = DecisionStatus.EXECUTED
                decision.result = {"canceled": True}
                await session.commit()
                
                logger.info(f"取消订单成功: order_id={order_id}")
                return None
                
        except Exception as e:
            logger.error(f"执行失败: {e}")
            decision.status = DecisionStatus.ERROR
            decision.reason = str(e)[:200]
            await session.commit()
            return None
    
    return None

